package com.ruoyi.common.redis.service;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.utils.LocalDateUtils;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;

/**
 * <p>
 * 作用：生成全局唯一key
 * </p>
 *
 * @author zhanglb1@tedu.cn
 * @since 2024-05-28 11:43
 */
@Component
public class GlobalKeyService {

  final int[] numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

  @Resource
  private RedisService redisService;
  final String GLOBAL_UNIQUE_KEY_PREFIX = "GLK";

  /**
   * 理论:支持最大每秒9999个key,并且单向增加
   * <p>
   * 数据组成形式:4位(年)+2位(月)+2位(日期)+2位(小时)+2位(分钟)+2位(秒)+4位(序列号)+1(随机号)
   * </p>
   */
  public Long globalKey() {
    return globalKeys(1).get(0);
  }

  public String globalKey(String prefix) {
    return globalKeys(prefix, 1).get(0);
  }

  /**
   * 理论:支持最大每秒9999个key,并且单向增加
   * <p>
   * 数据组成形式:4位(年)+2位(月)+2位(日期)+2位(小时)+2位(分钟)+2位(秒)+4位(序列号)+1(随机号)
   * </p>
   */
  public List<Long> globalKeys(int number) {
    final String cacheKey = LocalDateUtils.dateTimeFormat(LocalDateTime.now(), "yyyyMMddHHmmss");
    final Long increment = redisService.incrKey(cacheKey, number, 2, TimeUnit.SECONDS);
    final List<Integer> tails = randomTail(number);
    final List<Long> keys = new ArrayList<>();
    for (int i = (tails.size() - 1); i >= 0; i--) {
      keys.add(buildLongKey(cacheKey, tails.get(i), increment - i, 4));
    }
    return keys;
  }


  public List<String> globalKeys(String prefix, int number) {
    final String cacheKey = StrUtil.format("{}{}", prefix,
        LocalDateUtils.dateTimeFormat(LocalDateTime.now(), "yyyyMMddHHmmss"));
    final Long increment = redisService.incrKey(cacheKey, number, 2, TimeUnit.SECONDS);
    final List<Integer> tails = randomTail(number);
    final List<String> keys = new ArrayList<>();
    for (int i = (tails.size() - 1); i >= 0; i--) {
      keys.add(buildStrKey(cacheKey, tails.get(i), increment - i, 4));
    }
    return keys;
  }

  public List<Long> largeKeys(int number) {
    final String cacheKey = LocalDateUtils.dateTimeFormat(LocalDateTime.now(), "yyyyMMddHHmm");
    final Long increment = redisService.incrKey(cacheKey, number, 65, TimeUnit.SECONDS);
    final List<Integer> tails = randomTail(number);
    final List<Long> keys = new ArrayList<>();
    for (int i = (tails.size() - 1); i >= 0; i--) {
      keys.add(buildLongKey(cacheKey, tails.get(i), increment - i, 6));
    }
    return keys;
  }

  public List<Long> lakeKeys(int number) {
    final String cacheKey = LocalDateUtils.dateTimeFormat(LocalDateTime.now(), "96yyMMddHHmm");
    final Long increment = redisService.incrKey(cacheKey, number, 65, TimeUnit.SECONDS);
    final List<Integer> tails = randomTail(number);
    final List<Long> keys = new ArrayList<>();
    for (int i = (tails.size() - 1); i >= 0; i--) {
      keys.add(buildLongKey(cacheKey, tails.get(i), increment - i, 6));
    }
    return keys;
  }

  /**
   * 理论:支持最大每小时99999个key,并且单向增加,不适用高并发场景
   * <p>
   * 数据组成形式:prefix+4位(年)+2位(月)+2位(日期)+2位(小时)+6位(序列号)+1(随机号)
   * </p>
   */
  public String key20(String prefix) {
    return key20(prefix, 1).get(0);
  }

  /**
   * 理论:支持最大每小时99999个key,并且单向增加,不适用高并发场景
   * <p>
   * 数据组成形式:prefix+4位(年)+2位(月)+2位(日期)+2位(小时)+6位(序列号)+1(随机号)
   * </p>
   */
  public List<String> key20(String prefix, int number) {
    final String cacheKey = LocalDateUtils.dateTimeFormat(LocalDateTime.now(), "yyyyMMddHH");
    final Long increment = redisService.incrKey(cacheKey, number, 65, TimeUnit.MINUTES);
    final List<Integer> tails = randomTail(number);
    final List<String> keys = new ArrayList<>();
    for (int i = (tails.size() - 1); i >= 0; i--) {
      keys.add(
          StrUtil.format("{}{}", prefix, buildLongKey(cacheKey, tails.get(i), increment - i, 6)));
    }
    return keys;
  }

  public String sequencePerSeconds(String key, int digits) {
    return sequencePerSeconds(key, 1, digits).get(0);
  }


  public List<String> sequencePerSeconds(String key, int number, int digits) {
    final String cacheKey = StrUtil.format("{}{}", key,
        buildSequenceKey(LocalDateUtils.dateTimeFormat(LocalDateTime.now(), "yyyyMMddHHmmss")));
    final Long increment = redisService.incrKey(cacheKey, number, 2, TimeUnit.SECONDS);
    final List<String> keys = new ArrayList<>();
    for (int i = (number - 1); i >= 0; i--) {
      //处理格式
      keys.add(StrUtil.fillBefore(String.valueOf(increment - (long) i), '0', digits));
    }
    return keys;
  }

  private String buildSequenceKey(String key) {
    return StrUtil.format("SEQ{}", key);
  }

  private String buildStrKey(String head, Integer tail, Long sequence, int length) {
    return StrUtil.format("{}{}{}", head,
        StrUtil.padPre(String.valueOf(sequence), length, '0'), tail);
  }

  private Long buildLongKey(String head, Integer tail, Long sequence, int length) {
    return Long.valueOf(StrUtil.format("{}{}{}", head,
        StrUtil.padPre(String.valueOf(sequence), length, '0'), tail));
  }

  private List<Integer> randomTail(int number) {
    final Random random = new Random();
    final List<Integer> randomNumbers = new ArrayList<>();
    for (int i = 0; i < number; i++) {
      int randomIndex = random.nextInt(numbers.length);
      randomNumbers.add(numbers[randomIndex]);
    }
    return randomNumbers;
  }

}
